package nsn.excel.read.readmodel.base;


import nsn.excel.entity.ExcelPointer;
import nsn.excel.read.readmodel.AbstractModelExcelRead;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 基础写法：#{next:map:basics}
 *  1.next 为用户定义的方法名
 *  2.map 为类型 目前只提供两种 map 和 list
 *  3.为变量名称  如上面这个map名称为 basics
 * @author: caq
 * @description: excle 分行适配器
 * @createTime: 2021/5/10-21:44
 */
public class ModelExcelReadAdpter extends AbstractModelExcelRead {
    private static Logger logger = Logger.getLogger(ModelExcelReadAdpter.class.getName());



    /**
     *
     * 名称：定位指针
     * 规则：定位指针
     * 写法：#{location:map:basics:n}  n是偏移量
     * 定位
     * @author caq
     * @param sourceData 模板
     * @param targetData 数据源
     * @param excelPointer  模板的list 指针
     * @return   ExcelPointer 返回的包含的关系  ExcelPointer.start《= data《= ExcelPointer.End
     */
    public static ExcelPointer lastrowSite(ExcelPointer excelPointer, String[] configArry,List<Map<String, Object>> sourceData, List<Map<String, Object>>targetData) {
        Map<String, Object> sourceMap = sourceData.get(excelPointer.getIndex());
        for(int i=excelPointer.getEnd();i<targetData.size();i++){
            boolean flag = containsValue(sourceMap, targetData.get(i), excelPointer.getConfigKey());
            if(flag){
                excelPointer.setEnd(i);
            }
        }
        return excelPointer;
    }


    /**
     * @author caq
     * @param sourceData 模板
     * @param targetData 数据源
     * @param excelPointer  模板的list 指针
     * @return   ExcelPointer 返回的包含的关系  ExcelPointer.start《= data《= ExcelPointer.End
     */
    public static ExcelPointer atRow(ExcelPointer excelPointer, String[] configArry,List<Map<String, Object>> sourceData, List<Map<String, Object>>targetData) {
        //指定前进或者后退的行数 偏移量
        int offset=0;
        if(configArry.length>=4){
            offset=Integer.parseInt(configArry[3]);
        }
        excelPointer.setStart(excelPointer.getStart()+offset);
        excelPointer.setEnd(excelPointer.getEnd()+offset);
        return excelPointer;
    }





    /**
     * 药酱tips：
     *    100万的劳力士和10元的电子手表 时间是一样转的！
     *
     * 名称：中间匹配
     * 规则：根据上下行来匹配 中间内容
     * 写法：#{next:map:basics}
     * 实现： 通过找到电子手表 和劳力士的位置 来定位到中间这行
     *    1. 电子手表   10元     1只
     *    2. ${name}  ${price}  ${only}
     *    3. 劳力士    100万     1只
     *
     * @author caq
     * @param sourceData 模板
     * @param targetData 数据源
     * @param excelPointer  模板的list 指针
     * @return   ExcelPointer 返回的包含的关系  ExcelPointer.start《= data《= ExcelPointer.End
     */
    public static ExcelPointer autoMiddle(ExcelPointer excelPointer, String[] configArry,List<Map<String, Object>> sourceData, List<Map<String, Object>> targetData) {
        //上一行A单元格的值
        String on = sourceData.get(excelPointer.getIndex()-1).get("A")+"";
        //下一行A单元格的值
        String down = sourceData.get(excelPointer.getIndex()+1).get("A")+"";
        //找到上一行的坐标
        for(int i=excelPointer.getEnd();i<targetData.size();i++){
            if(on.equals(targetData.get(i).get("A")+""))
            {
                excelPointer.setStart(i+1);
                break;
            }
        }
        //找到下一行的坐标
        for(int i=excelPointer.getStart()+1;i<targetData.size();i++){
            if(down.equals(targetData.get(i).get("A")+""))
            {
                excelPointer.setEnd(i-1);
                break;
            }
        }
        return excelPointer;
    }

    /**
     * 名称：查找下一行为空的
     * 规则：查找下 N 行首列为空的数据
     * 写法：#{autoList:list:basics}  n是偏移量
     *
     * @author caq
     * @param sourceData 模板
     * @param targetData 数据源
     * @param excelPointer  模板的list 指针
     * @return   ExcelPointer 返回的包含的关系  《= data《=
     */
    public  static ExcelPointer autoList(ExcelPointer excelPointer, String[] configArry,List<Map<String, Object>> sourceData, List<Map<String, Object>> targetData) {

        for(int i=excelPointer.getEnd();i<targetData.size();i++){
            int emtpyCount=0;
            Map<String, Object> map = targetData.get(i);
            for (String key : map.keySet()) {
                //查找为空则跳出
                if (map.get(key)==null) {
                    emtpyCount++;
                }
            }
            //如果全空就结束了
            if(emtpyCount==map.size()){
                break;
            }
            excelPointer.setEnd(i);
        }
        return excelPointer;
    }


    /**
     * 名称：不为空
     * 规则：查找下 N 行首列为空的数据
     * 写法：#{findNotNull:list:basics}  n是偏移量
     *
     * @author caq
     * @param sourceData 模板
     * @param targetData 数据源
     * @param excelPointer  模板的list 指针
     * @return   ExcelPointer 返回的包含的关系  《= data《=
     */
    public  static ExcelPointer autoFirstMergeCells(ExcelPointer excelPointer, String[] configArry,List<Map<String, Object>> sourceData, List<Map<String, Object>> targetData) {
        //首行名称
        String startStr = sourceData.get(excelPointer.getIndex()).get("A").toString();
        //找到上一行的坐标
        for(int i=excelPointer.getEnd();i<targetData.size();i++){
            if(startStr.equals(targetData.get(i).get("A")+""))
            {
                excelPointer.setStart(i);
                break;
            }
        }
        //找到下一行的坐标
        for(int i=excelPointer.getStart()+1;i<targetData.size();i++){
            if(targetData.get(i).get("A")==null)
            {
                excelPointer.setEnd(i);
            }
        }
        return excelPointer;
    }



    @Override
    public ExcelPointer getPointer( ExcelPointer excelPointer, String[] configArry, List<Map<String, Object>> source, List<Map<String, Object>> target) {

        String action = configArry[0];
        Method method = null;
        //指针回归 向下指向 避免语法出错
            excelPointer.setEnd(excelPointer.getIndex()!=0?excelPointer.getEnd()+1:0);
            excelPointer.setStart(excelPointer.getEnd());
        try {
            method = this.getClass().getMethod(action, ExcelPointer.class, String[].class, List.class, List.class);
        } catch (NoSuchMethodException e) {
            logger.log(Level.ALL,"ExcelModelReadImpl指针方法未找到:" + action);
            e.printStackTrace();
        }
        try {
            method.invoke(this.getClass(), excelPointer, configArry, source, target);
        } catch (IllegalAccessException e) {
            logger.log(Level.ALL,"ExcelModelReadImpl没有方法权限:"+action);
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            logger.log(Level.ALL,"适配器: "+action+" 执行异常");
            e.printStackTrace();
        }

        return excelPointer;
    }

    /**
     * 比较Map是否相等
     * @param source
     * @param target
     * @param configKey
     * @return
     */
    private static boolean containsValue(Map<String,Object> source,Map<String,Object> target,String configKey){
        boolean flag=true;
        for (String key : source.keySet()) {
            if(configKey.equals(key))break;
            if(!(source.get(key)+"").equals(target.get(key)+"")){
                flag=false;
            }
        }
        return flag;
    }

}
